package org.jackysoft.service.impl;

import java.util.Collection;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jackysoft.bean.define.TransactionNames;
import org.jackysoft.data.AbstractDataProvider;
import org.jackysoft.entity.ActionNode;
import org.jackysoft.entity.OsStep;
import org.jackysoft.entity.OsWorkflowRunner;
import org.jackysoft.entity.WorkflowRunner;
import org.jackysoft.mapper.OsWorkflowRunnerMapper;
import org.jackysoft.service.OsWorkflowRunnerService;
import org.jackysoft.service.UserService;
import org.jackysoft.service.WorkflowNodeService;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Strings;

@Service
public class OsWorkflowRunnerServiceImpl extends AbstractDataProvider<OsWorkflowRunner>
		implements OsWorkflowRunnerService {
	// ~ Instance fields
	// ////////////////////////////////////////////////////////
	private static final Log log = LogFactory.getLog(OsWorkflowRunnerServiceImpl.class);
	
	
	@Resource
	private WorkflowNodeService nodeService;

	@Resource
	private UserService userService;
	
	
	@Resource
	OsWorkflowRunnerMapper mapper;
	
	
	// ~ Methods
	// ////////////////////////////////////////////////////////////////

	// ~ Getter/Setter
	// ////////////////////////////////////////////////////////////////

	public OsWorkflowRunnerServiceImpl() {
		super();
	}

	@Override
	public void setRunnerState(final long runnerId, final int state)
			 {
		mapper.updateState(runnerId, state);	
	}

	@Override
	public OsStep createCurrentStep(final long entryId, final long stepId,
			int actionId, final String owner, final long startDate,
			final long dueDate, final String status, final long[] previousIds)
			 {

		
		final OsStep step = new OsStep();
		mapper.insertStepId();
		long id  = mapper.selectStepId();
		step.setId(id);
		step.setStep(stepId);
		step.setAction(actionId);
		step.setOwner(owner);
		step.setCaller(owner);
		step.setStartDate(startDate);
		step.setDueDate(dueDate);
		step.setStatus(status);
		for (int i = 0; i < previousIds.length; i++) {
			mapper.insertCurrentPrev(id, previousIds[i]);
		}
		mapper.insertCurrentStep(step);
		return step;
	}

	@Override
	@Transactional(value=TransactionNames.IBATIS_TRANSACTION)
	public WorkflowRunner createRunner(String refname)
			 {
		final OsWorkflowRunner runner = new OsWorkflowRunner();
		runner.setState(WorkflowRunner.CREATED);
		runner.setRefname(refname);
		mapper.insertRunner(runner);
		return runner;
	}

	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public Collection<OsStep> findCurrentSteps(final long runner)  {
	    final Collection<OsStep> list = mapper.findAllCurrentStepByRunner(runner);
		return list;
	}

	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public WorkflowRunner findRunner(long id)  {
		WorkflowRunner runner = mapper.findRunner(id);
		
		return runner;
	}

	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public Collection<OsStep> findHistorySteps(final long runner)  {
		
		Collection<OsStep> list= mapper.findAllHistoryStepByRunner(runner);
		
		return list;
	}

	@Override
	public void markFinished(long step, int actionId, long finishDate,
			String status, String caller)  {
			
		mapper.markFinished(step, actionId, finishDate, status, caller);

	}

	@Override
	public void moveToHistory(final long  stepId)  {

	      mapper.moveToHistory(stepId);
		
	}	


	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public void reloadAll() {
		this.init();
	}

	// ~ Inner Interfaces
	// ///////////////////////////////////////////////////////

	// //////////////////////////////////////////////////////////////////
	// / 自定义方法
	// /
	// //////////////////////////////////////////////////////////////////
	@Override
	public void completeRunner(final long id) {
		changeRunnerState(id, WorkflowRunner.COMPLETED);	
	}

	@Override
	public void deleteRunner(final long id) {
		changeRunnerState(id, WorkflowRunner.KILLED);
	}

	

	@Override
	@Transactional(TransactionNames.IBATIS_TRANSACTION)	
	public void rollbackRunner(final long runner) {
		
		Collection<OsStep> currents = this.findCurrentSteps(runner);
		
		for(OsStep current :currents){
			if(current==null || current.getId()<=0)continue;
			long curid = current.getId();
			long hisid=mapper.findCurrentPrevId(curid);
			if(hisid<=0)continue;
			mapper.doRollbackStep(curid, hisid);
		}
		
	
	}
	

	@SuppressWarnings({ "rawtypes" })
	@Override
	@PostConstruct
	public void init()  {	
		

	}
	

	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public boolean stepIsStatus(long stepId, String status)
			 {

	    String from = mapper.findStatusOfCurrentStep(stepId); 

	    if(Strings.isNullOrEmpty(from))return false;
	    
	    return from.equalsIgnoreCase(status);
		
	}

	
	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public OsStep findHistoryStep(long id) {
		
		OsStep step = mapper.findCurrentStep(id);
		return step;
	}

	@Override
	@Transactional(value=TransactionNames.APP_TRANSACTION,readOnly = true)
	public OsStep findCurrentStep(long id)
			 {
		OsStep step = mapper.findHistoryStep(id);
		return step;

	}

	@Override
	public void removeCurrentStep(long stepId) {
		mapper.deleteCurrentStep(stepId);
	}

	
	void completeEntity(ActionNode action,final long id,Collection<OsStep> cursteps,final int state){
		
		for(OsStep step : cursteps){			
			String oldStatus = (action != null) ? action.getResultsNode().getUnconditionalResult().getOldStatus() : "Finished";
			markFinished(step.getId(),(action != null) ? action.getId() : (-1), DateTime.now().getMillis(),	oldStatus, step.getCaller());
			moveToHistory(step.getId());
		}		
		
	}
	
	@Override
	@Transactional
	public void changeRunnerState(long runnerId, int state) {
		
		int oldstate = mapper.findState(runnerId);
		if(canModifyRunnerState(runnerId,state)){
			setRunnerState(runnerId, state);
			if ((state == WorkflowRunner.KILLED)	|| (state == WorkflowRunner.COMPLETED)) {
				
				Collection<OsStep> currentSteps = findCurrentSteps(runnerId); 
				if (currentSteps.size() > 0) {
					completeEntity(null, runnerId, currentSteps, state);
				}
			}
		   
		}else{
			log.info(String.format("workflow %d state cannt change from %d to %d  ", runnerId,oldstate,state));
		}
		
	}
	

	@Override
	public boolean canModifyRunnerState(final long runnerId,final int newState) {
		
		int currentState = mapper.findState(runnerId);
		boolean result = false;

		switch (newState) {
		case WorkflowRunner.COMPLETED:

			if (currentState == WorkflowRunner.ACTIVATED) {
				result = true;
			}

			break;

		case WorkflowRunner.CREATED:
			result = false;

		case WorkflowRunner.ACTIVATED:

			if ((currentState == WorkflowRunner.CREATED)
					|| (currentState == WorkflowRunner.SUSPENDED)) {
				result = true;
			}

			break;

		case WorkflowRunner.SUSPENDED:

			if (currentState == WorkflowRunner.ACTIVATED) {
				result = true;
			}

			break;

		case WorkflowRunner.KILLED:

			if ((currentState == WorkflowRunner.CREATED)
					|| (currentState == WorkflowRunner.ACTIVATED)
					|| (currentState == WorkflowRunner.SUSPENDED)) {
				result = true;
			}

			break;

		default:
			result = false;

			break;
		}

		return result;
	}

	@Override
	public String findRunneRefname(long id) {
		// TODO Auto-generated method stub
		return null;
	}

}